﻿//
// Copyright (c) 2024 BPer
//
#include <bperrtp/BPerRtcpCompound.h>

#include <bperrtp/BPerRtcpSR.h>
#include <bperrtp/BPerRtcpRR.h>
#include <bperrtp/BPerRtcpXr.h>
#include <bperrtp/BPerRtcpSR.h>
#include <bperrtp/BPerRtcpPli.h>
#include <bperrtp/BPerRtcpSli.h>
#include <bperrtp/BPerRtcpNack.h>
#include <bperrtp/BPerRtcpTWCC.h>
#include <bperrtp/BPerRtcpRpsi.h>

#include <bperutil/sys/BPerLog.h>

bPer_vector_impl(BPerRtcpCommon)

void bPer_create_rtcpCompound(BPerRtcpCompound* rtcp){
	if(rtcp==NULL) return;
	bPer_create_BPerRtcpCommonVector(&rtcp->rtcpVector);

}
void bPer_destroy_rtcpCompound(BPerRtcpCompound* rtcp){
	if(rtcp==NULL) return;
	bPer_rtcpCompound_clear(rtcp);

}
int32_t bPer_decode_rtcpCompound(BPerRtcpCompound* rtcps,BPerBuffer *buffer){
	if(rtcps==NULL || buffer==NULL) return 1;
	int32_t err = BPer_Ok;
	rtcps->data = buffer->data;
	rtcps->nb_data = buffer->size;
	BPerRtcpHeader rtcpHeader={0};
	BPerRtcpHeader* header=&rtcpHeader;
	while (!bPer_buffer_empty(buffer)) {
		BPerRtcpCommon* rtcp = (BPerRtcpCommon*)bPer_calloc(1,sizeof(BPerRtcpCommon));
		bPer_decode_rtcpHeader(header,buffer->head);
		if (header->type == BPerRtcpType_sr) {
			bPer_create_rtcpSR(rtcp);
			err=bPer_decode_rtcpSR(rtcp,buffer);

		} else if (header->type == BPerRtcpType_rr) {
			bPer_create_rtcpRR(rtcp);
			err=bPer_decode_rtcpRR(rtcp,buffer);

		} else if (header->type == BPerRtcpType_rtpfb) {
			if(1 == header->rc) {
				//nack
				bPer_create_rtcpNack(rtcp,0);
				bPer_decode_rtcpNack(rtcp,buffer);

			} else if (15 == header->rc) {
				//twcc
				bPer_create_rtcptwcc(rtcp);
				bPer_twcc_rtcp_decode(rtcp,buffer);
			}
		} else if(header->type == BPerRtcpType_psfb) {
			if(1 == header->rc) {
				// pli
				bPer_create_rtcpPli(rtcp);
				err=bPer_decode_rtcpPli(rtcp,buffer);

			} else if(2 == header->rc) {
				//sli
				bPer_create_rtcpSli(rtcp,rtcp->ssrc);
				err=bPer_decode_rtcpSli(rtcp,buffer);

			} else if(3 == header->rc) {
				//rpsi
				bPer_create_rtcpRpsi(rtcp);
				bPer_decode_rtcpRpsi(rtcp,buffer);

			} else {
				// common psfb
				bPer_create_rtcpPsfb(rtcp);
				err=bPer_decode_rtcpPsfb(rtcp,buffer);

			}
		} else if(header->type == BPerRtcpType_xr) {
			bPer_create_rtcpXr(rtcp);
			err=bPer_decode_rtcpXr(rtcp,buffer);

		} else {
			bPer_create_rtcpCommon(rtcp);
			err=bPer_decode_rtcpCommon(rtcp,buffer);
		}


		if(err) {
			uint32_t header_type=rtcp->header.type;
			uint32_t header_rc=rtcp->header.rc;
			bPer_free(rtcp);
			if(err==ERROR_RTC_RTCP_EMPTY_RR)  {
				err=BPer_Ok;
				continue;
			}
			return bPer_error_wrap(err, "decode rtcp type=%u rc=%u", header_type, header_rc);
		}
		bPer_rtcpCompound_add_rtcp(rtcps,rtcp);
		bPer_free(rtcp);

	}

	return err;
}
int32_t bPer_encode_rtcpCompound(BPerRtcpCompound *rtcps, BPerBuffer *buffer) {
	if(rtcps==NULL) return 1;
	int32_t err = BPer_Ok;
	if (!bPer_buffer_require(buffer, rtcps->nb_bytes)) {
		return bPer_error_wrap(ERROR_RTC_RTCP, "requires %d bytes",
				rtcps->nb_bytes);
	}
	for (int i = 0; i < rtcps->rtcpVector.vsize; i++) {
		BPerRtcpCommon *rtcp = &rtcps->rtcpVector.payload[i];
		if (rtcp->header.type == BPerRtcpType_sr) {
			err = bPer_encode_rtcpSR(rtcp, buffer);
		} else if (rtcp->header.type == BPerRtcpType_rr) {
			err = bPer_encode_rtcpRR(rtcp, buffer);
		} else if (rtcp->header.type == BPerRtcpType_rtpfb) {
			if (1 == rtcp->header.rc) {
				//nack

				err=bPer_encode_rtcpNack(rtcp,buffer);
			} else if (15 == rtcp->header.rc) {
				//twcc

			}
		} else if (rtcp->header.type == BPerRtcpType_psfb) {
			if (1 == rtcp->header.rc) {
				// pli
				err = bPer_encode_rtcpPli(rtcp, buffer);
			} else if (2 == rtcp->header.rc) {
				//sli

			} else if (3 == rtcp->header.rc) {
				//rpsi
				err=bPer_encode_rtcpRpsi(rtcp,buffer);
			} else {
				// common psfb
				err = bPer_encode_rtcpPsfb(rtcp, buffer);
			}
		} else if (rtcp->header.type== BPerRtcpType_xr) {
			err = bPer_encode_rtcpXr(rtcp, buffer);
		} else {
			err = bPer_encode_rtcpCommon(rtcp, buffer);
		}

	}
	bPer_rtcpCompound_clear(rtcps);

	return err;
}
uint64_t bPer_rtcpCompound_nb_bytes(BPerRtcpCompound *rtcps){
	return kRtcpPacketSize;
}

int32_t bPer_rtcpCompound_add_rtcp(BPerRtcpCompound *rtcps, BPerRtcpCommon *rtcp)
{
	if(rtcps==NULL||rtcp==NULL) return 1;
	bPer_insert_BPerRtcpCommonVector(&rtcps->rtcpVector,rtcp);
	return BPer_Ok;
}
void bPer_rtcpCompound_clear(BPerRtcpCompound *rtcps)
{
	if(rtcps==NULL) return ;
	if(rtcps->rtcpVector.vsize){
		for(int i=0;i<rtcps->rtcpVector.vsize;i++){
			bPer_destroy_rtcpCommon(&rtcps->rtcpVector.payload[i]);
		}
		bPer_clear_BPerRtcpCommonVector(&rtcps->rtcpVector);
	}

}

